/*
 * Serializable.h
 *
 *  Created on: Sep 11, 2011
 *      Author: kimi
 */

#include "Serializador.h"

Serializador::Serializador(char* buffer, const unsigned int& buffer_length) :
		original_buffer_(buffer), buffer_(buffer + 1), buffer_length_(
				buffer_length) {
}

void Serializador::reset() {
	tamanio_buffer_escritura = 0;
	tamanio_buffer_lectura = 0;
	buffer_ = original_buffer_;
}

void Serializador::clear() {
	reset();
	for (unsigned int i = 0; i < buffer_length_; ++i) {
		buffer_[i] = 0;
	}
}

void Serializador::delete_internal_buffer() {
	delete[] original_buffer_;
	original_buffer_ = 0;
	buffer_ = 0;
}

unsigned int Serializador::length() {
	return tamanio_buffer_escritura;
}

bool Serializador::leer(char& output) {
	return leer_impl(output);
}
bool Serializador::leer(int& output) {
	return leer_impl(output);
}
bool Serializador::leer(unsigned long& output) {
	return leer_impl(output);
}
bool Serializador::leer(unsigned int& output) {
	return leer_impl(output);
}
bool Serializador::leer(float& output) {
	return leer_impl(output);
}
bool Serializador::leer(double& output) {
	return leer_impl(output);
}

bool Serializador::leer(std::string& output) {
	unsigned int length = 0;
	if (!leer_impl(length)) {
		return false;
	}

	if ((length + sizeof(unsigned int) + tamanio_buffer_lectura)
			> buffer_length_) {
		return false;
	}
	output.resize(length);
	std::copy(buffer_, buffer_ + length, output.begin());
	buffer_ += length;
	tamanio_buffer_lectura += length;
	return true;
}

bool Serializador::escribir(const char& _char) {
	return escribir_impl(_char);
}
bool Serializador::escribir(const int& _int) {
	return escribir_impl(_int);
}
bool Serializador::escribir(const unsigned int& _uint) {
	return escribir_impl(_uint);
}
bool Serializador::escribir(const unsigned long& _uint) {
	return escribir_impl(_uint);
}
bool Serializador::escribir(const float& _float) {
	return escribir_impl(_float);
}
bool Serializador::escribir(const double& _double) {
	return escribir_impl(_double);
}

bool Serializador::escribir(std::string& _str) {
	return escribir(_str.c_str(), static_cast<unsigned int>(_str.size()));
}

bool Serializador::escribir(const char* data, unsigned int length) {
	if ((length + sizeof(unsigned int) + tamanio_buffer_escritura)
			> buffer_length_) {
		return false;
	}
	escribir(length);
	std::copy(data, data + length, buffer_);
	buffer_ += length;
	tamanio_buffer_escritura += length;
	return true;
}

void Serializador::escribir_en_stream(std::ofstream& stream) {
	stream.write(original_buffer_, tamanio_buffer_escritura);
}

void Serializador::leer_de_stream(std::ifstream& stream,
		const unsigned int length) {
	if (length > buffer_length_) {
		return;
	}
	stream.read(original_buffer_, length);
}

void Serializador::escribir_en_buffer(char data[]) {
	std::copy(original_buffer_, original_buffer_ + tamanio_buffer_escritura,
			data);
}

void Serializador::leer_de_buffer(const char data[],
		const unsigned int& length) {
	if (length > buffer_length_) {
		return;
	}
	std::copy(data, data + length, original_buffer_);
}

template<typename T>
bool Serializador::escribir_impl(const T& data) {
	const unsigned int data_length = sizeof(T);
	if ((data_length + tamanio_buffer_escritura) > buffer_length_) {
		return false;
	}
	const char* ptr = reinterpret_cast<const char*>(&data);
	const char* end = reinterpret_cast<const char*>(&data) + sizeof(T);
	for (; ptr != end; ++buffer_, ++ptr) {
		*buffer_ = *ptr;
	}
	tamanio_buffer_escritura += data_length;
	return true;
}

template<typename T>
bool Serializador::leer_impl(T& data) {

	const unsigned int data_length = sizeof(T);
	if ((data_length + tamanio_buffer_lectura) > buffer_length_) {
		return false;
	}
	char* ptr = reinterpret_cast<char*>(&data);
	char* end = reinterpret_cast<char*>(&data) + sizeof(T);
	for (; ptr != end; ++buffer_, ++ptr) {
		*ptr = *buffer_;
	}
	tamanio_buffer_lectura += data_length;
	return true;
}
